/**
 * @file task_misc.c
 * @brief 
 * @author henry.cai (henry.cai@queclink.com)
 * @version 1.0
 * @date 2024-09-05
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-05 <td>1.0     <td>henry.cai     <td>内容
 * </table>
 */

#include <stdio.h>
#include "global.h"
#include "bsp_rtc.h"

#include "task_misc.h"
#include "version.h"

#include "cmsis_os2.h"
#include "FreeRTOS.h"
#include "task.h"
#include "portmacro.h"
extern void vPortSysTickDisable( void );
extern void vPortSysTickEnable( void );
extern void vTaskStepStoppedTick( const TickType_t xTicksToJump );

    #define portDISABLE_TICK_TIMER()        vPortSysTickDisable()
    #define portENABLE_TICK_TIMER()         vPortSysTickEnable()
    #define portDISABLE_INTERRUPTS_ALL()    portDISABLE_INTERRUPTS()
    #define portENABLE_INTERRUPTS_ALL()     portENABLE_INTERRUPTS()

#include "misc_log.h"
#include "misc_event.h"
#include "hwmisc.h"
#include "bsp.h"
#include "misc/rtc_app.h"

#include "aadl/include/aadl/flash.h"

#include "misc/misc_print.h"
#include "service/include/swei_cache.h"
#include "service/include/swei_status.h"
#include "lowpower/include/low_power.h"
#include "misc/misc_system.h"
#include "comm/co_heartbeat.h"
#include "flash/key_params/key_api.h"


device_param_t  dev_prm = {0};  // 存放设备运行参数
device_status_t dev_sta = {0};  // 存放设备运行状态

static misc_info_t misc_info;

/* 存储到FLASH的杂项 */
misc_save_t misc_save;


void sec1st_load2ram(void);
void misc_param_flash2ram(void);

/**
 * @brief 应答上位机升级结果
 */
void transmit_upgrade_result(void)
{
    uint8_t fota_type = 0;

    fota_type = misc_read_fota_type();

    /* 根据升级标志返回升级成功和失败，默认失败返回升级超时，后续更新为升级失败错误码 */
    extern int32_t ymodem_write(void *data, int32_t len);
    char result[64] = {0};
    if (strncmp(dev_sta.mcu.fota_mark, FOTA_OK_STR, strlen(FOTA_OK_STR)) == 0) {
        /* 更新成功，上报固件升级成功 */
        snprintf(result, sizeof(result), "\r\n+OTARES:%u,0,%u\r\n", (fota_type == 1) ? 1 : 0, 0);

        // 升级结果为了避免发送不出去, 增加发送次数为3
        ymodem_update_result_send(result, strlen(result));

        log_i("FOTA OK, send the ota result to PC!\r\n");
        strcpy(dev_sta.mcu.fota_mark, FOTA_IDLE_STR);

        /* 升级完成上报设备版本信息以及备用电池基本信息 */
        swei_status_event_update(TBOX_UPLOAD_DEV_VERSION, 0);
        if (is_backup_batt_insert())
            swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_BACK_INFO, 1);
        
        save_fota_idle();
    } else if (strncmp(dev_sta.mcu.fota_mark, FOTA_ERR_STR, strlen(FOTA_ERR_STR)) == 0) {
        char result[8] = {0};
        /* 更新失败 */
        snprintf(result, sizeof(result), "\r\n+OTARES:%u,0,%u\r\n", (fota_type == 1) ? 1 : 0, ETIMEDOUT); // 0 means iot firmware type

        // 升级结果为了避免发送不出去, 增加发送次数为3
        ymodem_update_result_send(result, strlen(result));

        log_e("FOTA FAIL, send the ota result to PC!\r\n");
        strcpy(dev_sta.mcu.fota_mark, FOTA_IDLE_STR);
        save_fota_idle();
    }
}

static TaskHandle_t misc_handle;
void task_misc_entry(void *param);

/// @brief 设备初始化
/// @param  
/// @return 
int32_t misc_device_init(void)
{
    /* 1. 开机读取硬件版本 */
    misc_read_hwver();

    /* 2. 第一分区数据读取, 读取设备参数 sec1st_load2ram*/
    sec1st_load2ram();

    /* 3. 读取其他设备参数fatal_load2ram */
    misc_param_flash2ram();

    /* 4. 应答升级结果 */
    transmit_upgrade_result();

    /* 4. 显示开机信息 */
    show_poweron_info();
    
    /* 5. 创建设备杂项数据线程，用于监听事件和处理杂项数据更新 */
    if(pdPASS != xTaskCreate(task_misc_entry, "misc", TASKSTACK_MISC, NULL, TASKPRI_MISC, &misc_handle))
    {
        Error_Handler();
    }

    
    return 0;
}


/// @brief 杂项初始化
/// @param  
void task_misc_init(void)
{
    misc_event_init();

	rtc_app_init();
}


#include "lettershell/shell.h"
bool shell_sleep_enable = false;                /* 默认先关闭, 后续所有功能没有问题后, 在默认开启 */
//bool shell_sleep_enable = true;

int32_t cmd_sleep_enable(void)
{ 
    shell_sleep_enable = true;
    return 0;
}
int32_t cmd_sleep_disable(void)
{ 
    shell_sleep_enable = false;
    return 0;
}

bool cmd_sleep_status_get(void)
{
    return shell_sleep_enable;
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | SHELL_CMD_DISABLE_RETURN,
                 sleep_enable, cmd_sleep_enable, sleep enable);
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | SHELL_CMD_DISABLE_RETURN,
                 sleep_disable, cmd_sleep_disable, sleep disable);

#include "service/include/swei_login.h"
#include "utils/utils_timer.h"
#include "bsp/inc/bsp_rtc.h"
/*  具体逻辑
*  1.使用亚秒进行ms计时,使用bsp_rtc_get()进行秒计时.
*  2.亚秒计数是递减计数器,且与bsp_rtc_get()时同步一致,即亚秒计数为0时, bsp_rtc_get()就立刻+1.
*  3.STOP进入前和STOP退出后都会进行亚秒对齐.
*  4.通过STOP前的亚秒、秒和STOP后的亚秒、秒计算出STOP时长.
*/
typedef struct {
    bool is_run_err;                            /* 判断当前RTC时钟是否发生运行错误. */
    unsigned int prestop_subsec;                /* 进入Stop前的亚秒数. */
    unsigned int subsec_cnt_total;              /* 亚秒预装载值. */
    unsigned int subsec_us_offset;              /* 记录上次Stop结束后,Stop的补偿,用于下次Stop. 单位: us */
} subsec_cps_t;

static subsec_cps_t _subsec_cps;
static subsec_cps_t *subsec_cps = &_subsec_cps;

volatile static bool is_wakeup_ready = false;          /* 判断当前唤醒时钟是否就绪正常. */
volatile static unsigned int rtc_sec_cnt = 0;          /* RTC唤醒的次数,周期1s. */

typedef struct {
    bool is_int_exit;                           /* 是否中断退出. */
    bool is_stopping;                           /* 判断当前是否处于stop模式中,用于非RTC中断的其他中断补偿. */
    unsigned int last_stop;                     /* 最近一次是STOP时长,单位ms. */
    unsigned int prestop_sec;                   /* 进入Stop前的秒数. */
    unsigned int prestop_wakeupsec;             /* 进入Stop前的唤醒秒数. */
    unsigned int lowpwr_wakeup_mark;            /* 低功耗唤醒源标志 */
} lowpwr_cps_t;

static lowpwr_cps_t _lowpwr_cps;
static lowpwr_cps_t *lowpwr_cps = &_lowpwr_cps;
/*
 * @brief  进入stop前的参数初始化.
 * @param  param: [I], 低功耗任务的参数;
 * @note   1.当返回值为false表示初始化失败,系统不能进入stop模式.
 *         2.本函数会进行亚秒对齐和失能systick定时器.
 *         3.不用考虑对齐后,RTC计时+1,以为1亚秒的时间足够执行完.
 * @retval ture:初始化成功, false: 初始化失败.
 */
 #if defined __ICCARM__ /* IAR */
#pragma optimize=none
#endif /* __ICCARM__ */
bool lowpwr_prestop_init_subsec(void)
{
    unsigned int subsec = 0;
    unsigned int align_subsec = 0;

    align_subsec = bsp_rtc_subsecond_get(); /* 亚秒对齐 */

    do {
        subsec = bsp_rtc_subsecond_get();
    } while (subsec == align_subsec);

    portDISABLE_TICK_TIMER();                /* 在此失能systick定时器,因为下面的运行时间用RTC定时器计时. */

    // struct tm pre_time;
    // if (0 != bsp_rtc_get(&pre_time))
    //     return false;

    subsec_cps->prestop_subsec = subsec;
    subsec_cps->is_run_err = false;
    subsec_cps->subsec_cnt_total = bsp_rtc_subsecond_reload() + 1;
    lowpwr_cps->prestop_wakeupsec = rtc_sec_cnt;
    lowpwr_cps->prestop_sec = get_timestamp(); //mktime(&pre_time);
    lowpwr_cps->is_stopping = true;

    return true;
}

#include "lowpower/include/low_power.h"  
void rtc_wakeup_isr(void)
{
    is_wakeup_ready = true;
    rtc_sec_cnt    += lowpower_sleep_sec_get();
    // rtc_wakeup_isr_hook();
}

/*
 * @brief  STOP期间,获取此刻已走的STOP时长.
 * @note   1.此时亚秒还未对齐,固亚秒需要自加1,亚秒对齐是在stop退出时进行对齐.
 * @retval 返回ms.
 */
unsigned int lowpwr_stopping_ms_get_subsec(void)
{
    if (!lowpwr_cps->is_stopping)
        return 0;

    if (subsec_cps->is_run_err)         /* 若RTC故障,则采用唤醒计时. */
        return (rtc_sec_cnt - lowpwr_cps->prestop_wakeupsec) * 1000;

    unsigned int ms = 0;
    unsigned int subsec = 0;
    unsigned int curr_subsec = bsp_rtc_subsecond_get();
//    struct tm post_time;
    // if(0 == bsp_rtc_get(&post_time)) {
        ms = (unsigned int)(difftime(get_timestamp(), lowpwr_cps->prestop_sec) * 1000);
        if (curr_subsec <= subsec_cps->prestop_subsec) {
            subsec = subsec_cps->prestop_subsec - curr_subsec;
        } else if (1000 <= ms) {    /* 当curr_subsec > subsec_cps->prestop_subsec,说明亚秒已经发送了重新装载 */
            ms -= 1000;
            subsec = subsec_cps->subsec_cnt_total - curr_subsec + subsec_cps->prestop_subsec;
        } else {
            goto _err;
        }

       ms += ((subsec + 1) * 1000 / subsec_cps->subsec_cnt_total);  /* 亚秒还未对齐,固加1. */
    // } else {
    //     goto _err;
    // }

    if (ms + 5000 <= (rtc_sec_cnt - lowpwr_cps->prestop_wakeupsec) * 1000)  /* 若RTC秒数增值小于唤醒秒数增值5s,则认为RTC计数异常. */
        goto _err;

    return ms;

_err:
    subsec_cps->is_run_err = true;

    return (rtc_sec_cnt - lowpwr_cps->prestop_wakeupsec) * 1000;
}

/*
 * @brief  退出stop.
 * @param  param: [I], 低功耗任务的参数;
 * @note   1.本函数会进行亚秒对齐和使能systick定时器.
 *         2.不用考虑对齐后,RTC计时+1,以为1亚秒的时间足够执行完.
 * @retval ture:初始化成功, false: 初始化失败.
 */
#if defined __ICCARM__ /* IAR */
#pragma optimize=none
#endif /* __ICCARM__ */
void lowpwr_poststop_exit_subsec(void)
{
    unsigned int stop_ms = 0;
    volatile unsigned int subsec = 0;
    volatile unsigned int align_subsec = 0;
    align_subsec = bsp_rtc_subsecond_get();     /* 对齐 SubSecond 时退出 STOP */

    do {
        subsec = bsp_rtc_subsecond_get();
    } while (subsec == align_subsec);

    portENABLE_TICK_TIMER();

    struct tm post_time;
    if(!subsec_cps->is_run_err && 0 == bsp_rtc_get(&post_time)) {
        stop_ms = (unsigned int)(difftime(get_timestamp(), lowpwr_cps->prestop_sec) * 1000);
        if (align_subsec <= subsec_cps->prestop_subsec) {
            subsec = subsec_cps->prestop_subsec - align_subsec;
        } else if (1000 <= stop_ms) {
            stop_ms -= 1000;
            subsec = subsec_cps->subsec_cnt_total - align_subsec + subsec_cps->prestop_subsec;
        } else {
            subsec_cps->is_run_err = true;
        }

        if (!subsec_cps->is_run_err) {
            stop_ms += (subsec * 1000 / subsec_cps->subsec_cnt_total);
            subsec_cps->subsec_us_offset += (subsec * 1000 * 1000 / subsec_cps->subsec_us_offset) % 1000;
            stop_ms += subsec_cps->subsec_us_offset / 1000;
            subsec_cps->subsec_us_offset = subsec_cps->subsec_us_offset % 1000;
        }
    } else {
        subsec_cps->is_run_err = true;
    }

    if (subsec_cps->is_run_err) {
        stop_ms = (rtc_sec_cnt - lowpwr_cps->prestop_wakeupsec) * 1000;
    }

    portDISABLE_INTERRUPTS_ALL();
    vTaskStepStoppedTick(_MS2TICKS(stop_ms));
    lowpwr_cps->is_stopping = false;
    portENABLE_INTERRUPTS_ALL();

    if (subsec_cps->is_run_err) {
        char err_info[72] = {0};
        sprintf(err_info, "The RTC counter appears inaccurate during the low power!\r\n");
        record_syserr(err_info);
    }

    is_wakeup_ready = false;
    lowpwr_cps->last_stop = stop_ms;
}


TickType_t xTaskGetStoppingTickCount( void )
{
    return lowpwr_stopping_ms_get_subsec();
}
/// @brief 杂项任务函数
/// @param  
void task_misc_process(void)
{
    /* 1. 处理系统事件 */
    misc_event_process();
    
    /* 2. 处理系统数据 */
    misc_fix_report_process();

    /* 3. 处理打印数据 */
    // misc_print_process();

    /* 4. 定时保存杂项数据到FLASH */
    misc_save_data_to_flash();

    /* 5. 系统事件处理 */
    misc_system_event_process();
}

/// @brief misc 处理线程
/// @param  
void task_misc_entry(void *param)
{
    log_i("task_misc_entry entry!\r\n");
    task_misc_init();

    while(1)
    {
        task_misc_process();
        vTaskDelay((100));
    }
}

/**
 * @brief 判断buf是否为全数字
 * @param  buf              My Param doc
 * @param  cnt              My Param doc
 * @return true 
 * @return false 
 */
bool is_all_numeric(const char *buf, size_t cnt)
{
    int i;

    if ((NULL == buf) || (!cnt))
        return false;

    for (i=0; i < cnt; i++) {
        if (('0' > buf[i]) || ('9' < buf[i]))
            return false;
    }

    return true;
}

/*******************************************************************************
 * 函数名称：imei_str_is_valid
 * 功能描述：检测IMEI字符串是否有效
 * 输入参数：imei_str imei字符串  size 字符串大小
 * 返 回 值：true 有效  false 无效
 ******************************************************************************/
static bool imei_str_is_valid(char* imei_str, int size)
{
    #define IMEI_STR_MAX_SIZE  (15)

    if (size != IMEI_STR_MAX_SIZE)
        return false;

    return is_all_numeric(imei_str, size);
}



#include "flash/key_params/key_params.h"
#include "flash/protocol_params/protocol_params.h"
extern void mmgr_imei_set(char *imei);
extern int32_t load_quec_sn(char *sn, ssize_t len);
extern int8_t load_apn_key_params(apn_param_t *apn, ssize_t apn_len);
extern int8_t load_imei(char *imei, ssize_t imei_len);
/**
 * @brief 第一分区初始化
 */
void sec1st_load2ram(void)
{
    /* 1.读取fota状态标记*/
    load_fota_flag(dev_sta.mcu.fota_mark, sizeof(dev_sta.mcu.fota_mark));
    log_i("read fota flag from flash: %s\r\n", dev_sta.mcu.fota_mark);
    
    /* 2. 读取SN参数 移为SN + 客制SN */
    load_quec_sn(dev_prm.quec_sn, sizeof(dev_prm.quec_sn));   // 移为SN
    if(config_get(CONFIG_ID_SN, &dev_prm.sn) < 0) {
        log_e("load sn failed, please use AT+WSN to set sn!\r\n");
    }
    log_i("read sn from flash: %s\r\n", dev_prm.sn);

    /* 3. 读取APN参数 */
    apn_param_t apn = {0};
    if(0 == load_apn_key_params(&apn, sizeof(apn_param_t)))
    {
        strcpy(dev_prm.apn.name, apn.name);
        strcpy(dev_prm.apn.user, apn.user);
        strcpy(dev_prm.apn.pwd, apn.pwd);
    }
    log_i("read apn(name) from flash: %s\r\n", dev_prm.apn.name);
    log_i("read apn(user) from flash: %s\r\n", dev_prm.apn.user);
    log_i("read apn(pwd) from flash: %s\r\n", dev_prm.apn.pwd);
    
    /* 4.读取存储的IMEI号 */
    if (0 == load_imei(dev_prm.imei, sizeof(dev_prm.imei))) {
        if (imei_str_is_valid(dev_prm.imei, strlen(dev_prm.imei)) == true)
            mmgr_imei_set(dev_prm.imei);
    }

    // /* 3.读取网络频道配置信息 */
    // rd_len = sec1st_flash_read(FLASH_MODME_NETAND_ADDR,
    //                           (unsigned char *)&bandp,
    //                            sizeof(struct f_network_config));
    // if (rd_len > 0) {
    //     crc_cal = qlsdk_crc16_ccitt((const unsigned char*)&bandp,
    //                                  sizeof(struct f_network_config) - 2);
    //     if(bandp.crc == crc_cal){
    //         net_data_conversion(&bandp, &g_sec1st_info.net_cfg);
    //     }
    // }

    // /* 4.读取gnss的配置信息 */
    // rd_len = sec1st_flash_read(FLASH_GNSS_CFG_ADDR,
    //                           (unsigned char *)&gnss_cfg,
    //                            sizeof(struct f_gnss_config));
    // if (rd_len > 0) {
    //     crc_cal = qlsdk_crc16_ccitt((const unsigned char*)&gnss_cfg,
    //                                  sizeof(struct f_gnss_config) - 2);
    //     if(gnss_cfg.crc == crc_cal){
    //         g_sec1st_info.gnss_mode = 0;
    //         if (gnss_cfg.gnss_mode & F_GNSS_GPS) {
    //             g_sec1st_info.gnss_mode |= GNSS_GPS;
    //         }
    //         if (gnss_cfg.gnss_mode & F_GNSS_GLONASS) {
    //             g_sec1st_info.gnss_mode |= GNSS_GLONASS;
    //         }
    //         if (gnss_cfg.gnss_mode & F_GNSS_GALILEO) {
    //             g_sec1st_info.gnss_mode |= GNSS_GALILEO;
    //         }
    //         if (gnss_cfg.gnss_mode & F_GNSS_BEIDOU) {
    //             g_sec1st_info.gnss_mode |= GNSS_BEIDOU;
    //         }
    //     }else{
	// 		qlprintf("flash not save gnss cfg\r\n");
	// 	}
    // }

    // /* 5.读取fota次数信息 */
    // rd_len = sec1st_flash_read(FLASH_FOTA_CNT_ADDR,
    //                           (unsigned char *)&g_sec1st_info.fota_cnt,
    //                            sizeof(g_sec1st_info.fota_cnt));
    // if (rd_len < 0 || g_sec1st_info.fota_cnt < 0) {
    //     g_sec1st_info.fota_cnt = 0;
    // }

    //  /* 6.读取存储的item 号 */
    // rd_len = sec1st_flash_read(FLASH_ITEM_NO_ADDR,
    //                           (unsigned char *)item_str,
    //                            sizeof(item_str)-1);
    // if (rd_len > 0) {
    //     if (item_no_str_is_valid(item_str, strlen(item_str)) == true)
    //         strcpy(g_sec1st_info.item_no,item_str);
    // }

    // /* 7.读取存储的设备密码 */
    // rd_len = sec1st_flash_read(FLASH_DEV_PWD_ADDR,
    //                           (unsigned char *)&pwd_str,
    //                            sizeof(f_pwd_cfg_t));
    // sec1st_data_crypto(false, (unsigned char *)&pwd_str, sizeof(f_pwd_cfg_t));
    // if (rd_len > 0) {
    //     crc_cal = qlsdk_crc16_ccitt((const unsigned char*)&pwd_str,
    //                                  sizeof(f_pwd_cfg_t) - 2);
    //     if (pwd_str.crc == crc_cal && dev_pwd_str_is_valid(pwd_str.pwd, strlen(pwd_str.pwd)) == true)
    //         strcpy(g_sec1st_info.dev_pwd, pwd_str.pwd);
    // }
    
    // /* 8.读取存储的网络模式APN配置参数 */
    // rd_len = sec1st_flash_read(FLASH_APN_ADDR,
    //                           (unsigned char *)&f_apn_cfg,
    //                            sizeof(f_apn_cfg));
    // sec1st_data_crypto(false, (unsigned char *)&f_apn_cfg, sizeof(f_apn_cfg));
    // if (rd_len > 0) {
    //     crc_cal = qlsdk_crc16_ccitt((const unsigned char*)&f_apn_cfg,
    //                                  sizeof(f_apn_cfg) - 2);
    //     if (f_apn_cfg.crc == crc_cal) {			/* 检验不对，不更新 */
    //         memcpy(&g_sec1st_info.apn_cfg,&f_apn_cfg,sizeof(apn_cfg_t));
	// 		apn_cfg_err_flag = false;
    //     }else{
	// 		apn_cfg_err_flag = true;
	// 	}
    // }

    // /* 9.读取存储的设备IOT模式 */
    // rd_len = sec1st_flash_read(FLASH_DEV_IOT_MODE_ADDR,
    //                           (unsigned char *)&iot_mode,
    //                            sizeof(iot_mode));
    // if (rd_len > 0) {
    //     if (dev_iot_mode_is_valid(iot_mode) == true)
    //         g_sec1st_info.iot_mode = iot_mode;
    //     else
    //         g_sec1st_info.iot_mode = DEV_TEST_MODE;
    // }

	// /* 10.读取存储的网络异常代码 */
	// unsigned char mdm_lost = 0;
    // rd_len = sec1st_flash_read(FLASH_MDM_LAST_ERROR_ADDR,
    //                           (unsigned char *)&mdm_lost,
    //                            sizeof(unsigned char));
    // if (rd_len > 0) {
	// 	g_sec1st_info.mdm_lost = mdm_lost;
    // }
	// qlprintf("The last socket disconnection reason:%u\r\n", g_sec1st_info.mdm_lost);


    // /* 11.读取存储的设备密码 */
    // rd_len = sec1st_flash_read(FLASH_BLE_PWD_ADDR,
    //                           (unsigned char *)&pwd_str,
    //                            sizeof(f_pwd_cfg_t));
    // sec1st_data_crypto(false, (unsigned char *)&pwd_str, sizeof(f_pwd_cfg_t));
    // if (rd_len > 0) {
    //     crc_cal = qlsdk_crc16_ccitt((const unsigned char*)&pwd_str,
    //                                  sizeof(f_pwd_cfg_t) - 2);
    //     if (pwd_str.crc == crc_cal && dev_pwd_str_is_valid(pwd_str.pwd, strlen(pwd_str.pwd)) == true)
    //         strcpy(g_sec1st_info.ble_pwd, pwd_str.pwd);
    // }

    // /* 12.读取首扇区固件加密信息 */
    // sec1st_load2ram_fw_enc_key();
}




#include "flash/protocol_params/protocol_params.h"
/**
 * @brief flash其他信息加载
 */
void misc_param_flash2ram(void)
{
    /** 读取盲区数据 */
    swei_cache_load();
}

/**
 * @brief flash其他信息保存
 */
void misc_param_ram2flash(void)
{
    /** 保存盲区数据 */
    swei_cache_flush();
}


/**
 * 读取保存杂项数据
 */
void misc_read_data_from_flash(void)
{
    // int i = 0;
    int ret = 0;

    /* 读取总ACC点火时间 */
    ret = aad_flash_frequency_read(FREQ_MISC_DATA_ID, (unsigned char *) &misc_save);

    if ((ret <= 0) || (MISC_WRITE_FLASH_END != misc_save.save_flag)) {
        log_e("misc data read failed [%d], set to default.\r\n", ret);
        memset(&misc_save, 0, sizeof(misc_save));
        misc_save.save_flag = 0;
        misc_save.rtc_flag  = 0;
    } 
}

/**
 * 保存杂项数据
 */
int misc_write_data_to_flash(void)
{
    int result = 0;
    char try_cnt = 0;

    misc_save.save_flag = MISC_WRITE_FLASH_END;


#if 0
    for(int i = 0; i<MAX_OUTPUT_NUM; i++) {
        printf("adp_duration_write_test %d %u, H%u, L%u, %u, %u.\r\n", i, misc_save_adp.output[i].status, misc_save_adp.output[i].duration_h, misc_save_adp.output[i].duration_l, \
            misc_save_adp.output[i].toggle_times, misc_save_adp.output[i].long_time);
    }
#endif
    
RETRY_SAVE:
    /* 保存总ACC点火时间 */
    result = aad_flash_frequency_write(FREQ_MISC_DATA_ID, (unsigned char *) &misc_save, 0, 0);
    if (result < 0) {
        try_cnt++;
        log_e("Misc task write data to flash error result=%d!\r\n, try cnt:%d.", result, try_cnt);
        if(try_cnt <= 3) {
            goto RETRY_SAVE;
        }
    }

    return result;
}


/**
 * MISC读取保存数据
 */
void misc_flash_data_init(void)
{
    misc_read_data_from_flash();
    rtc_update_from_flash();
}

/**
 * 每隔300S保存一次数据数据
 */
void misc_save_data_to_flash(void)
{
    if (!timeout_sec(misc_info.save_interval, MISC_SAVE_INTERVAL))
        return;

    misc_write_data_to_flash();
    misc_info.save_interval = getsec();
}



/**
 * @brief 保存升级类型
 * @param  fota_type        My Param doc
 */
void misc_save_fota_type(uint8_t fota_type)
{
    misc_info.fota_type = fota_type;
}



/**
 * @brief 读取升级类型
 * @param  fota_type        My Param doc
 */
uint8_t misc_read_fota_type(void)
{
    return misc_info.fota_type;
}

/**
 * @brief 读取移为SN
 * @return const char* 移位定制SN
 */
const char *misc_read_quec_sn(void)
{
    if(strlen(dev_prm.quec_sn) == 0) {
        // 尝试读取
        load_quec_sn(dev_prm.quec_sn, sizeof(dev_prm.quec_sn));   // 移为SN
        if(strlen(dev_prm.quec_sn) == 0) {
            return "";
        }
    }

    return dev_prm.quec_sn;
}